/* 
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2010. All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:  Use,
 * duplication or disclosure restricted by GSA ADP Schedule
 * Contract with IBM Corp.
 *
 * This code is released under the terms of the Eclipse Public License
 * version 1.0 which can be found at the top level of this project or
 * or at http://www.eclipse.org/org/documents/epl-v10.php
 */

package com.ibm.mining;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import com.ibm.mining.model.*;

import com.ibm.team.repository.common.IContributor;
import com.ibm.team.scm.common.IChangeSet;

public abstract class ResearchDatabase {
	public Connection conn;
	
	public abstract Connection connect(String jdbcConnectionString) throws SQLException;
	public void commit() throws SQLException {
		conn.commit();
	}
	
	public void dropTablesForModel(Model model) throws SQLException {
		for (ModelClass modelClass : model.getModelClasses().values()) {
			dropTablesForModelClass(modelClass);
		}
	}
	
	public void dropTablesForModelClass(ModelClass modelClass) throws SQLException {
		dropTable(new TableData(modelClass.getName().toLowerCase()));
		
		// now drop one-to-many tables for properties that are lists
		for (Property prop : modelClass.getProperties()) {
			if (prop.getType().isListItemType()) {
				String tableName = modelClass.getName().toLowerCase() + "_to_" + 
					prop.getName().toLowerCase();
				dropTable(new TableData(tableName));
			}
		}
		/* drop the table that tracks history if indeed this modelclass
		 * has its history tracked
		 */
		if (modelClass.isHistoryTracked()) {
			String tableName = modelClass.getName().toLowerCase() + "_history";
			dropTable(new TableData(tableName));
		}
	}

	public void createTablesForModel(Model model) throws SQLException{
		createTablesForModel(model, false);
	}
	
	/* if onlyOutput is true, then it will only output the sql needed
	 * to create the tables and will not actually create them
	 */
	public void createTablesForModel(Model model, boolean onlyOutput) throws SQLException{
		for (ModelClass modelClass : model.getModelClasses().values()) {
			createTablesForModelClass(modelClass, onlyOutput);
		}
	}

	public void createTablesForModelClass(ModelClass modelClass) throws SQLException {
		createTablesForModelClass(modelClass, false);
	}

	public void createTablesForModelClass(ModelClass modelClass, boolean onlyOutput) throws SQLException {
		TableData td = new TableData(modelClass.getName().toLowerCase());
		for (Property prop : modelClass.getProperties()) {
			Type propType = prop.getType();
			/* if this property is a primitive type then add a column corresponding to that type */
			if (propType.isPrimitiveType()) {
				td.columns.add(Pair.of(prop.getName().toLowerCase(), prop.getType()));
			/* but if this property is another jazz entity then add a column for each key that that entity
			 * has so that we can join this table with the table for that entity
			 */
			} else if (propType.isModelClassType()) {
				ModelClass otherClass = propType.getModelClassForType();
				for (String key : otherClass.getKeys() ) {
					td.columns.add(Pair.of(prop.getName() + "_" + key, otherClass.getProperty(key).getType()));
				}
			}
		}
		td.keys = modelClass.getKeys();
		createTable(td, onlyOutput);

		// now create one-to-many tables for properties that are lists
		for (Property prop : modelClass.getProperties()) {
			if (prop.getType().isListItemType()) {
				String tableName = modelClass.getName().toLowerCase() + "_to_" + 
					prop.getName().toLowerCase();
				td = new TableData(tableName);
				Type listItemType = prop.getType().getListItemType();
				for (String key : modelClass.getKeys()) {
					Property keyProp = modelClass.getProperty(key);
					td.columns.add(Pair.of(modelClass.getName().toLowerCase() + "_" + key, keyProp.getType()));
				}
				if (listItemType.isPrimitiveType()) {
						td.columns.add(Pair.of(Util.getSingular(prop.getName()), listItemType));
				} else {
					ModelClass otherClass = listItemType.getModelClassForType();
					for (String key : otherClass.getKeys()) {
						String colName = Util.getSingular(prop.getName()) + "_" +
							otherClass.getName().toLowerCase() + "_" + key;
						td.columns.add(Pair.of(colName, otherClass.getProperty(key).getType()));
					}
				}
				createTable(td, onlyOutput);
			}
		}
		
		// if the history for this class is tracked, then create the tables
		// for that now
		if (modelClass.isHistoryTracked()) {
			String tableName = modelClass.getName().toLowerCase() + "_history";
			td = new TableData(tableName);
			Type stringType = modelClass.getModel().getType("String");
			Type timestampType = modelClass.getModel().getType("Timestamp");
			td.columns.add(Pair.of("modified_by", stringType));
			td.columns.add(Pair.of("modified", timestampType));
			td.columns.add(Pair.of("property", stringType));
			td.columns.add(Pair.of("change_type", stringType));
			td.columns.add(Pair.of("old_val", stringType));
			td.columns.add(Pair.of("new_val", stringType));
			for (String key : modelClass.getKeys()) {
				td.columns.add(Pair.of(modelClass.getName().toLowerCase() + "_" + key, stringType));
			}
			createTable(td, onlyOutput);
		}
	}
	
	public abstract void dropTable(TableData tableData) throws SQLException;
	public abstract void createTable(TableData tableData, boolean onlyOutput) throws SQLException;
	
}
